/*
 * @Description: 表格操作
 * @Author: James324
 * @Date: 2023-09-06 15:05:45
 * @LastEditors: James324
 * @LastEditTime: 2024-04-01 17:35:24
 */
import { cloneDeep } from 'lodash-es';
import {
    getArrIdListToIds,
    getDom,
    generateId,
    getParentToSelector,
    getElCssValue,
    hideValidErrText
} from '@/utils';
import { Modal, Message } from '@/instance';
import type { BaseTableProps } from '../type';
import { TableRefs } from 'element-plus';

interface DeprecationParam {
    props: BaseTableProps;
    editRef: Ref<boolean>;
    tableData: Ref<any>;
    emit: any;
    tableItems: any[];
    expand: Ref<any>;
    errValidRef: Ref<any>;
    setInit: (val: boolean) => void;
}

/**
 * @: 初始化新增数据结构
 */
export const initAddRow = () => {
    const id = generateId();
    return {
        id: id,
        edit: true,
        visible: false,
        unAction: true
    };
};

/**
 * @: 设置默认值
 */
export const initDefault = (obj: anyObj, tableItems: any[]) => {
    if (!tableItems) return;
    for (const item of tableItems) {
        if (item.default !== undefined) {
            obj[item.modelKey!] = item.default;
        }
    }
};

/**
 * @: 保存接口调用成功后的操作
 */
export const saveSuccess = (row: any, oldRow: any, tableRef: Ref<TableRef | undefined>) => {
    if (!tableRef.value) return;
    for (const attr in row) {
        if (attr.includes('te__mp')) {
            row[attr] = row[attr.replace('te__mp', '')];
        }
    }
    oldRow.edit = false; // 还原编辑状态
    tableRef.value.editRef = false; // 将编辑状态置为false
    tableRef.value.getCellAddData();
};

export function useTableAction(
    tableRef: Ref<TableRefs | null | undefined>,
    { props, editRef, tableData, emit, tableItems, expand, setInit, errValidRef }: DeprecationParam
) {
    /**
     * 获取处理后的表格数据
     */
    const getPostTableData = async (row: any) => {
        const arr: any[] = cloneDeep(tableData.value);

        for (const item of arr) {
            for (const attr in item) {
                if (attr.includes('te__mp')) {
                    delete item[attr];
                }
            }
        }

        const filterArr = arr.filter((item: any) => item.id === row.id);

        emit('change', filterArr[0], row);
    };

    /**
     * 编辑保存
     */
    const confirmEdit = (
        row: any,
        rowIndex: number,
        valid: (...args: any) => boolean | undefined
    ) => {
        if (!valid(row, rowIndex)) return;
        getPostTableData(row);
    };

    /**
     * 取消编辑
     */
    const cancelEdit = async (row: any) => {
        try {
            Modal.confirm({
                title: '数据未保存，确定取消？',
                content: '取消后将会放弃本次填写的内容',
                type: 'warning',
                onOk: () => {
                    row.edit = !row.edit;
                    editRef.value = row.edit;
                    for (const attr in row) {
                        if (!attr.includes('te__mp')) {
                            row[attr] = row[attr + 'te__mp'];
                        }
                    }
                }
            });
        } catch (e: any) {
            throw new Error('发生了错误', e);
        }
    };

    /**
     * 表格操作项中删除
     */
    const deleteAction = (row: any, index: number) => {
        emit('del', row, index);
        getCellAddData();
    };

    /**
     * 新增表格行
     */
    const isInit = ref(true); // 初始化默认添加一条数据
    const obj: anyObj = {};
    const add = () => {
        if (tableData.value.length >= props.maxAddNum!) {
            Message.error(props.addTip || '最多只能批量增加 50 条数据！');
            return;
        }

        // 表格行添加自定义钩子
        if (typeof props.beforeAddValidFn === 'function' && !props.beforeAddValidFn()) return;
        initDefault(obj, tableItems); // 设置默认值

        const obj1 = Object.assign({}, obj, initAddRow());

        for (const attr in obj1) {
            const temp = `${attr}te__mp`;
            obj1[temp] = obj1[attr];
        }

        if (props.mode === 'bottom') {
            tableData.value.push(obj1);
        }
        if (props.mode === 'top') {
            tableData.value.unshift(obj1);
        }

        emit('add', tableData.value);
        // 处于单元编辑状态，赋值 isInit 变量用于 initWatchData 初始化 watch 监听表格数据变化时是否新增一条新单元数据项
        if (props.cellEdit) {
            const initValue = tableData.value.every((item: any) => item.unAction);
            setInit(initValue);
        }

        nextTick(() => {
            scrollToTableBottom();
        });
    };

    /**
     * 点击表格编辑
     */
    const handleEdit = (row: any) => {
        emit('edit', row);
        if (props.lineEdit || props.cellEdit) {
            // 存储一个临时变量
            for (const item of tableData.value) {
                // TODO: 后期可扩展只编辑当前传入 id 的单元选项
                if (props.editableKeys?.includes(item.id)) {
                    item.edit = true;
                }

                for (const attr in item) {
                    if (attr === 'edit') continue;
                    const temp = `${attr}te__mp`;
                    item[temp] = item[attr];
                }
            }

            row.edit = !row.edit;
            editRef.value = row.edit;
        }
    };

    /**
     * 表格多选行
     */
    const selectTableMultiData = ref<any[]>([]);
    const handleSelectionChange = (list: any[]) => {
        if (!props.addTableRow) {
            emit('selectionChange', list);
        } else {
            selectTableMultiData.value = list.map((item: any) => item.id);
        }
    };

    /**
     * 表格单选行
     */
    const selectTableRowData = ref<any[]>([]);
    const handleCurrentChange = (currentRow: any) => {
        selectTableRowData.value = currentRow;
    };

    /**
     * 批量删除表格行
     */
    const isDel = ref(false);
    const cellAddData = ref([]);
    const handleBatchDelete = () => {
        if (!selectTableMultiData.value.length) {
            Message.error('请选择需要删除的选项！');
            return;
        }

        // 实时监听表单校验文案提示
        hideValidErrText(() => {
            errValidRef.value = null;
        }, tableRef.value!.$el);

        isDel.value = true;
        let cellEditData = [];
        let matchedEditIds = [];
        // 表格处于单元编辑时，批量删除行过滤需要删除给后端的 id 列表，剔除新增的单元数据，
        if (props.cellEdit) {
            cellEditData = tableData.value.filter((item: any) => !item.unAction);
            matchedEditIds = getArrIdListToIds(cellEditData, selectTableMultiData.value);
            if (matchedEditIds.length) emit('del', matchedEditIds);
        }

        getCellAddData();
        const matchedAddIds = getArrIdListToIds(cellAddData.value, selectTableMultiData.value);
        const delAddData = cellAddData.value.filter(
            (data: any) => !matchedAddIds.includes(data.id)
        );

        tableData.value = props.cellEdit ? [...cellEditData, ...delAddData] : delAddData;

        clearSelection(); // 清空选择
        getCellAddData(); // 更新新增单元选项数据，防止数据删除了未更新导致的数据错乱

        if (!tableData.value.length) add();

        nextTick(() => {
            isDel.value = false; // 还原
        });
    };

    /**
     * 获取单元新增的数据
     */
    const getCellAddData = () => {
        cellAddData.value = tableData.value.filter((item: any) => item.unAction);
    };

    /**
     * 删除新增表格当前选项行
     */
    const handleDeleteRow = (row: any) => {
        isDel.value = true;
        tableData.value = tableData.value.filter((data: any) => {
            return data.id !== row.id;
        });

        const editTableData = tableData.value.filter((data: any) => data.edit); // 只对当前可编辑的选项作处理

        clearSelection(); // 清空选择
        Message.success('删除成功！');

        if (!editTableData.length) add();

        nextTick(() => {
            isDel.value = false;
        });
    };

    /**
     * 清空表格选择
     */
    const clearSelection = () => {
        tableRef.value?.clearSelection();
    };

    /**
     * 表格所处行是否允许选择
     */
    const handleSelectable = (item: any, index: number) => {
        if (props.selectable) {
            return props.selectable(item, index);
        }
        if (!props.addTableRow) return true;
        if (tableData.value.length === 1 && !index) {
            return false;
        }
        return true;
    };

    /**
     * 初始化表格数据
     */
    const initWatchTableData = () => {
        // 默认将字段未空字符串 '' 转换为 null 方便第一次校验使用
        for (const item of tableItems) {
            tableData.value.forEach(() => {
                if (!obj[item.modelKey!]) {
                    obj[item.modelKey!] = null;
                }
            });
        }

        watch(
            () => tableData.value,
            val => {
                if (!val) {
                    tableData.value = [];
                    return;
                }

                if (props.addTableRow) {
                    if (isDel.value) return; // 处于删除状态不做添加操作, 解决出现重复添加新增选项问题
                    nextTick(() => {
                        if (isInit.value) {
                            add();
                        }
                    });
                }
            },
            {
                immediate: true
            }
        );
    };

    /**
     * 获取动态展示表格属性列表
     */
    const tableConfigProp = tableItems.map((item: any) => item.modelKey);

    /**
     * 获取只传入给后端表格属性数据，排除不必要的字段
     */
    const getSaveData = () => {
        const copyTableData = cloneDeep(tableData.value);
        // 默认 id 与 unAction 字段不处理，方便后面数据逻辑判断，id 提供给后端接口使用，unAction 提供给处于单元编辑状态剔除不是新增数据
        const handleData = copyTableData.map((item: any) => {
            if (!props.cellEdit) {
                delete item['id'];
                delete item['unAction'];
            }

            for (const key in item) {
                if (key !== 'id' && key !== 'unAction' && !tableConfigProp.includes(key)) {
                    delete item[key];
                }
            }
            return item;
        });
        const saveData = props.cellEdit
            ? handleData
                  .filter((item: any) => item.unAction) // 剔除不是新增数据
                  .map((item: any) => {
                      delete item['unAction'];
                      return item;
                  })
            : handleData;
        return saveData;
    };

    /**
     * 设置表格多选选中状态
     */
    const toggleRowSelection = (row: anyObj, checked: boolean) => {
        nextTick(() => {
            tableRef.value?.toggleRowSelection(row, checked);
        });
    };

    /**
     * 设置表格展开行
     */
    const toggleRowExpansion = (row: anyObj) => {
        // 默认展开时，需将展开状态默认设置为 true
        if (props.tableAttr?.defaultExpandAll) {
            return;
        } else {
            row.expand = !row.expand;
            tableToggleRowExpansion(row, row.expand);
        }
    };

    const tableToggleRowExpansion = (row: anyObj, expand: boolean) => {
        tableRef.value?.toggleRowExpansion(row, expand);
    };

    /**
     * 点击当前行
     */
    const handleRowClick = (row: any, column: any, event: any) => {
        // 存在表格展开行或展开自己树，执行对应点击行展开操作
        if (props.tableConfig.expand || props.tableAttr?.treeProps) {
            toggleRowExpansion(row);
        }
        emit('row-click', row, column, event);
    };

    /**
     * 设置表格单选选中状态
     */
    const setCurrentRow = (row?: anyObj) => {
        nextTick(() => {
            tableRef.value?.setCurrentRow(row);
        });
    };

    /**
     * modal 框全屏模式，滚动条处理逻辑
     */
    const modalFullscreenFn = (tableWrapper: HTMLElement) => {
        const modalBody = getParentToSelector(tableWrapper, '.m-modal__body') as HTMLElement;
        const childNodes = Array.from(modalBody?.childNodes);
        const childNode = childNodes.filter((child: ChildNode) => child.nodeType === 1); // 过滤处为 元素节点 的节点类型
        const modalTable = childNode[0] as HTMLElement;
        const modalBodyRect = modalBody?.getBoundingClientRect();
        const modalTableRect = modalTable?.getBoundingClientRect();
        const modalBodyPaddingTop = parseInt(getElCssValue(modalBody!, 'padding-top'));
        const modalBodyPaddingBottom = parseInt(getElCssValue(modalBody!, 'padding-bottom'));

        if (
            modalTableRect.height >
            modalBodyRect.height - (modalBodyPaddingTop + modalBodyPaddingBottom)
        ) {
            modalBody.scrollTo({
                top: modalTableRect.height,
                left: 0,
                behavior: 'smooth'
            });
        }
    };

    /**
     * modal 框非全屏模式，滚动条处理逻辑
     */
    const modalNoFullscreenFn = () => {
        const scrollView = getDom('.el-scrollbar__wrap', tableRef.value?.$el);
        const scrollEl = getDom('.el-scrollbar__view', tableRef.value?.$el);
        const scrollHeight = scrollEl?.scrollHeight || 0;
        if (scrollHeight > parseInt(scrollView?.style.maxHeight as string)) {
            tableRef.value?.setScrollTop(scrollHeight);
        }
    };

    /**
     * moddal 框模式，滚动条滚至最底部
     */
    const modalScrollToBottom = () => {
        const elTableWrapper = getDom('.el-table__inner-wrapper', tableRef.value?.$el);

        if (elTableWrapper?.style.maxHeight === '100%') {
            // 全屏模式
            modalFullscreenFn(elTableWrapper);
        } else {
            // 非全屏
            modalNoFullscreenFn();
        }
    };

    /**
     * 详情页全屏模式，滚动条处理逻辑
     */
    const detailFullscreenFn = () => {
        const MPage = getDom('.m-page');
        const LTable = getDom('.l-table');
        const MPageRect = MPage?.getBoundingClientRect();
        const LTableRect = LTable?.getBoundingClientRect();
        const LTableDiffHeight = LTableRect!.height + LTableRect!.top;

        if (LTableDiffHeight > MPageRect!.height) {
            MPage!.scrollTo({
                top: LTableDiffHeight,
                left: 0,
                behavior: 'smooth'
            });
        }
    };

    /**
     * 详情页非全屏模式，滚动条处理逻辑
     */
    const detailNoFullscreenFn = () => {
        const LContentMain = getDom('.l-content__main');
        const LContentMainTable = getDom('.l-content--main');
        const LContentMainRect = LContentMain?.getBoundingClientRect();
        const LContentMainTableRect = LContentMainTable?.getBoundingClientRect();
        const LContentMainPBottom = parseInt(getElCssValue(LContentMain!, 'padding-bottom'));
        const LContentDiffHeight =
            LContentMainTableRect!.height +
            (LContentMainTableRect!.top - LContentMainRect!.top) +
            LContentMainPBottom;

        if (LContentDiffHeight > LContentMainRect!.height) {
            LContentMain!.scrollTo({
                top: LContentDiffHeight,
                left: 0,
                behavior: 'smooth'
            });
        }
    };

    /**
     * 详情页模式
     */
    const detailScrollToBottom = () => {
        if (expand.value) {
            detailFullscreenFn(); // 全屏
        } else {
            detailNoFullscreenFn(); // 非全屏
        }
    };

    /**
     * 页面自动滚动至底部
     */
    const scrollToTableBottom = () => {
        if (props.modalMode) {
            modalScrollToBottom(); // modal 弹框模式
        } else if (props.openSticky) {
            detailScrollToBottom(); // 详情页模式
        }
    };

    /**
     * 动态设置表格某列的宽度
     * @param {string} modelKey 表头字段名
     * @param {number} width 列宽
     */
    const setAsyncColumnWidth = (modelKey: string, width: number) => {
        tableItems.map(item => {
            if (item.modelKey === modelKey) {
                item.columnProps.width = width;
            }
        });
    };

    return {
        confirmEdit,
        cancelEdit,
        deleteAction,
        add,
        handleEdit,
        handleSelectionChange,
        handleCurrentChange,
        handleDeleteRow,
        handleBatchDelete,
        handleRowClick,
        initWatchTableData,
        selectTableMultiData,
        selectTableRowData,
        handleSelectable,
        toggleRowSelection,
        toggleRowExpansion,
        tableToggleRowExpansion,
        setAsyncColumnWidth,
        setCurrentRow,
        getSaveData,
        isInit,
        getCellAddData,
        clearSelection,
        initAddRow
    };
}
